﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;

namespace LINQPad.OpenAccess.UI.ViewModel
{
    /// <summary>
    /// Abstract base class for view model implementations.
    /// </summary>
    public abstract class ViewModelBase : INotifyPropertyChanged, IDisposable
    {
        #region Private

        #region - Vars

        [DebuggerBrowsable( DebuggerBrowsableState.Never )]
        private bool _isDisposed;

        #endregion

        #endregion

        #region Protected

        #region - Functions

        /// <summary>
        /// Releases unmanaged and - optionally - managed resources.
        /// </summary>
        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
        protected virtual void Dispose( bool disposing )
        {
            this._isDisposed = true;
        }
        /// <summary>
        /// Disposes the field.
        /// </summary>
        /// <typeparam name="T">The type of the field.</typeparam>
        /// <param name="field">The field.</param>
        protected virtual void DisposeField<T>( ref T field )
            where T : IDisposable
        {
            if ( field != null )
            {
                field.Dispose( );
                field = default( T );
            }
        }
        /// <summary>
        /// Called when a property has changed.
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        protected virtual void OnPropertyChanged( string propertyName )
        {
            var handler = this.PropertyChanged;
            if ( handler != null )
                handler( this, new PropertyChangedEventArgs( propertyName ) );
        }
        /// <summary>
        /// Called when a property has changed.
        /// </summary>
        /// <typeparam name="T">The type of the property.</typeparam>
        /// <param name="propertySelector">The property selector.</param>
        protected void OnPropertyChanged<T>( Expression<Func<T>> propertySelector )
        {
            if ( propertySelector == null )
                throw new ArgumentNullException( "propertySelector" );
            this.OnPropertyChanged( ( ( MemberExpression ) propertySelector.Body ).Member.Name );
        }
        /// <summary>
        /// Throws an exception if the current instance is disposed.
        /// </summary>
        /// <exception cref="System.ObjectDisposedException">If the instance is disposed.</exception>
        protected virtual void ThrowIfDisposed( )
        {
            if ( this.IsDisposed )
                throw new ObjectDisposedException( this.GetType( ).FullName );
        }

        #endregion

        #region - Properties

        /// <summary>
        /// Gets a value indicating whether this instance is disposed.
        /// </summary>
        /// <value>
        /// <c>true</c> if this instance is disposed; otherwise, <c>false</c>.
        /// </value>
        protected virtual bool IsDisposed
        {
            get
            {
                return this._isDisposed;
            }
        }

        #endregion

        #endregion

        #region INotifyPropertyChanged Members

        /// <summary>
        /// Occurs when after a property has changed.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        #region IDisposable Members

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose( )
        {
            this.Dispose( true );
            GC.SuppressFinalize( this );
        }

        #endregion
    }
}
